using System;
using System.Collections.Generic;
using System.Text;

namespace Msrp.Message
{
    public class MessageChunk : Message
    {
        public enum REPORT
        {
            NO,
            PARTIAL,
            YES
        }
        public void addPacket(BufferParser.Buffer fBuffer)
        {
            mBufferList.Add(fBuffer);
            if (fBuffer.endOfChunkIdx != -1) // last buffer of the chunk
            {
                assemble();
                parse();
                mIsCompleted = true;
            }
        }

        public bool IsCompleted
        {
            get { return mIsCompleted; }
        }

        private int assemble()
        {
            // count the buffer needed to hod whole chunk
            int size = 0;
            for (int i = 0; i < mBufferList.Count; i++ )
            {
                if (mBufferList[i].endOfChunkIdx != -1)
                {
                    size += mBufferList[i].endOfChunkIdx;
                } 
                else
                {
                    size += mBufferList[i].dataBuffer.Length;
                }
            }
            m_buff = new byte[size];

            // copy the data to the single chunk;
            int currNextIdx = 0; 
            for (int i = 0; i < mBufferList.Count; i++)
            {
                if (mBufferList[i].endOfChunkIdx != -1)
                {
                    Array.Copy(mBufferList[i].dataBuffer, 0, m_buff, currNextIdx, mBufferList[i].endOfChunkIdx);
                    currNextIdx += mBufferList[i].endOfChunkIdx;
                }
                else
                {
                    Array.Copy(mBufferList[i].dataBuffer, 0, m_buff, currNextIdx, mBufferList[i].dataBuffer.Length);
                    currNextIdx += mBufferList[i].dataBuffer.Length;
                }
            }
            return size;

        }

        private bool parse()
        {
            int fromIdx = 0;
            int toIdx;
            string line = getLine(m_buff, fromIdx, out toIdx);
            parseFirstLine(line);


            string[] tokens = line.Split(":".ToCharArray());
            if(tokens[0] == "Byte-Range")
            {
                m_byteRange.parse(tokens[1]);
            }
            else if (tokens[0] == "Message-ID")
            {
                MessageId = tokens[1];
            }
            else if (tokens[0] == "Success-Report")
            {
                if(tokens[1].ToLower() == "no")
                {
                    m_successReport = REPORT.NO;
                }
                else if (tokens[1].ToLower() == "yes")
                {
                    m_successReport = REPORT.YES;
                }
                else
                {
                    return false;
                }
            }
            else if (tokens[0] == "Failure-Report")
            {
                if (tokens[1].ToLower() == "no")
                {
                    m_failureReport = REPORT.NO;
                }
                else if (tokens[1].ToLower() == "yes")
                {
                    m_failureReport = REPORT.YES;
                }
                else if (tokens[1].ToLower() == "partial")
                {
                    m_failureReport = REPORT.PARTIAL;
                }
                else
                {
                    return false;
                }
            }
            else if (tokens[0] == "To-Path")
            {
                string[] uris = tokens[1].Split(" ".ToCharArray());
                foreach(string uri in uris)
                {
                    Msrp.Uri msrpUri = new Msrp.Uri(uri);
                    m_toPath.Add(msrpUri);
                }
            }
            else if (tokens[0] == "From-Path")
            {
                string[] uris = tokens[1].Split(" ".ToCharArray());
                foreach (string uri in uris)
                {
                    Msrp.Uri msrpUri = new Msrp.Uri(uri);
                    m_fromPath.Add(msrpUri);
                }
            }


            return true;
        }

        //private int getLine(byte[] buff, int fFromIdx)
        //{
        //    Byte cr = (Byte)'\r';
        //    Byte lf = (Byte)'\n';
        //    for (int i = fFromIdx; i < buff.Length - 1; i++)
        //    {
        //        if (buff[i] == cr && buff[i+1] == lf)
        //        {
        //            return i + 1;
        //        }
        //    }
        //    return -1;
        //}

        private string getLine(byte[] buff, int fFromIdx, out int fOutToIdx)
        {
            Byte CR = (Byte)'\r';
            Byte LF = (Byte)'\n';
            for (int i = fFromIdx; i < buff.Length - 1; i++)
            {
                if (buff[i] == CR && buff[i + 1] == LF)
                {
                    fOutToIdx = i + 2;
                    ASCIIEncoding ae = new ASCIIEncoding();
                    char[] chbuff = new char[ae.GetCharCount(buff)];                    
                    return new string(ae.GetChars(buff, fFromIdx, i - fFromIdx));                    
                }
            }
            fOutToIdx = -1;
            return null;
        }


        // first line may have the following formats
        // 
        private bool parseFirstLine(string fLine)
        {
            string msrp;
            int responseCode;
            string responseText;

            string[] tokens = fLine.Split(" ".ToCharArray());
            if(tokens.Length == 4) // response message
            {
                msrp = tokens[0];
                m_transacId = tokens[1];
                responseCode = Int16.Parse(tokens[2]);
                responseText = tokens[3];

            }
            else if (tokens.Length == 3) // request message
            {
                msrp = tokens[0];
                m_transacId = tokens[1];
                method = tokens[2];
            }
            else
            {
                return false;
            }
            return true;
        }

        private List<BufferParser.Buffer> mBufferList = new List<BufferParser.Buffer>();
        private bool mIsCompleted = false;
        byte[] m_buff;
        string m_transacId;
        string method;
        REPORT m_successReport = REPORT.NO; // default
        REPORT m_failureReport = REPORT.YES;  // default
        ByteRange m_byteRange = new ByteRange();
        private List<Msrp.Uri> m_toPath = new List<Msrp.Uri>();
        private List<Msrp.Uri> m_fromPath = new List<Msrp.Uri>();
        bool completeChunk = false;
    }
}
